~ chicken-core (chicken-5) /manual/Module (chicken syntax)
Trap1[[tags: manual]]2[[toc:]]34== Module (chicken syntax)56This module has support for syntax- and module handling. This module7is used by default, unless a program is compiled with the8{{-explicit-use}} option.910=== Macro transformers1112Macro transformers are procedures you can use in a {{define-syntax}}13context to register a procedure that can transform s-expressions into14other s-expressions. Only use these when you need to break hygiene in15a controlled way; for many use cases {{syntax-rules}} is more16appropriate, as it offers stronger guarantees of hygiene, is more17high-level and is standard R5RS Scheme.1819For those situations where you need more control, however, CHICKEN20supports two kinds of low-level macros: so-called explicit renaming21and implicit renaming macros.2223==== Explicit renaming macros2425The low-level macro facility that CHICKEN provides is called "explicit26renaming" and allows writing hygienic or non-hygienic macros27procedurally. When given the return value of one of the28procedures {{er-macro-transformer}} or {{ir-macro-transformer}}29instead of a {{syntax-rules}} form, {{define-syntax}} evaluates the30procedure in a distinct expansion environment (initially having access31to the exported identifiers of the {{scheme}} module). The procedure32takes an expression and two other arguments and returns a transformed33expression.3435For example, the transformation procedure for a {{call}} macro such36that {{(call proc arg ...)}} expands into {{(proc arg ...)}} can be37written as3839 (er-macro-transformer40 (lambda (exp rename compare)41 (cdr exp)))4243Expressions are represented as lists in the traditional manner,44except that identifiers are represented as special uninterned symbols.4546The second argument to a transformation procedure is a renaming procedure that47takes the representation of an identifier as its argument and returns the48representation of a fresh identifier that occurs nowhere else in the49program. For example, the transformation procedure for a simplified50version of the {{let}} macro might be written as5152 (er-macro-transformer53 (lambda (exp rename compare)54 (let ((vars (map car (cadr exp)))55 (inits (map cadr (cadr exp)))56 (body (cddr exp)))57 `((lambda ,vars ,@body)58 ,@inits))))5960This would not be hygienic, however. A hygienic {{let}} macro must61rename the identifier {{lambda}} to protect it from being captured by62a local binding. The renaming effectively creates a fresh alias for63{{lambda}}, one that cannot be captured by any subsequent binding:6465 (er-macro-transformer66 (lambda (exp rename compare)67 (let ((vars (map car (cadr exp)))68 (inits (map cadr (cadr exp)))69 (body (cddr exp)))70 `((,(rename 'lambda) ,vars ,@body)71 ,@inits))))7273The expression returned by the transformation procedure will be74expanded in the syntactic environment obtained from the syntactic75environment of the macro application by binding any fresh identifiers76generated by the renaming procedure to the denotations of the original77identifiers in the syntactic environment in which the macro was78defined. This means that a renamed identifier will denote the same79thing as the original identifier unless the transformation procedure80that renamed the identifier placed an occurrence of it in a binding81position.8283Identifiers obtained from any two calls to the renaming procedure with84the same argument will necessarily be the same, but will denote the85same syntactical binding. It is an error if the renaming procedure is86called after the transformation procedure has returned.8788The third argument to a transformation procedure is a comparison89predicate that takes the representations of two identifiers as its90arguments and returns true if and only if they denote the same thing91in the syntactic environment that will be used to expand the92transformed macro application. For example, the transformation93procedure for a simplified version of the {{cond}} macro can be written94as9596 (er-macro-transformer97 (lambda (exp rename compare)98 (let ((clauses (cdr exp)))99 (if (null? clauses)100 `(,(rename 'quote) unspecified)101 (let* ((first (car clauses))102 (rest (cdr clauses))103 (test (car first)))104 (cond ((and (symbol? test)105 (compare test (rename 'else)))106 `(,(rename 'begin) ,@(cdr first)))107 (else `(,(rename 'if)108 ,test109 (,(rename 'begin) ,@(cdr first))110 (,(rename 'cond) ,@rest)))))))))111112In this example the identifier {{else}} is renamed before being passed113to the comparison predicate, so the comparison will be true if and114only if the test expression is an identifier that denotes the same115thing in the syntactic environment of the expression being transformed116as {{else}} denotes in the syntactic environment in which the {{cond}}117macro was defined. If {{else}} were not renamed before being passed to118the comparison predicate, then it would match a local variable that119happened to be named {{else}}, and the macro would not be hygienic.120The final recursive call to {{cond}} also needs to be renamed because121someone might create an alias for this macro and use it in a {{let}}122where {{cond}} is an ordinary variable.123124Some macros are non-hygienic by design. For example, the125following defines a {{loop}} macro that implicitly binds {{exit}} to an126escape procedure. The binding of {{exit}} is intended to capture free127references to {{exit}} in the body of the loop, so {{exit}} is not128renamed.129130 (define-syntax loop131 (er-macro-transformer132 (lambda (x r c)133 (let ((body (cdr x)))134 `(,(r 'call-with-current-continuation)135 (,(r 'lambda) (exit)136 (,(r 'let) ,(r 'f) () ,@body (,(r 'f)))))))))137138Suppose a {{while}} macro is implemented using {{loop}}, with the intent139that {{exit}} may be used to escape from the {{while}} loop. The {{while}}140macro cannot be written as141142 (define-syntax while143 (syntax-rules ()144 ((while test body ...)145 (loop (if (not test) (exit #f))146 body ...))))147148because the reference to {{exit}} that is inserted by the {{while}} macro149is intended to be captured by the binding of {{exit}} that will be150inserted by the {{loop}} macro. In other words, this {{while}} macro is151not hygienic. Like {{loop}}, it must be written using procedurally:152153 (define-syntax while154 (er-macro-transformer155 (lambda (x r c)156 (let ((test (cadr x))157 (body (cddr x)))158 `(,(r 'loop)159 (,(r 'if) (,(r 'not) ,test) (exit #f))160 ,@body)))))161162Think about it: If we ''did'' rename {{exit}}, it would refer to an163{{exit}} procedure existing in the context of the macro's definition.164That one [[Unit library#exit|actually exists]]; it is the procedure165that exits the Scheme interpreter. Definitely ''not'' the one we want :)166So now we make it refer to an {{exit}} that's locally bound in the167environment where the macro is expanded.168169Note: this implementation of explicit-renaming macros allows passing170arbitrary expressions to the renaming and comparison procedures. When171being renamed, a fresh copy of the expression will be produced, with all172identifiers renamed appropriately. Comparison also supports arbitrary173expressions as arguments.174175176===== er-macro-transformer177178<procedure>(er-macro-transformer TRANSFORMER)</procedure>179180Returns an explicit-renaming macro transformer procedure created from181the procedural macro body {{TRANSFORMER}}, which is a procedure of182three arguments.183184This procedure will be called on expansion with the complete185s-expression of the macro invocation, a rename procedure that186hygienically renames identifiers and a comparison procedure that187compares (possibly renamed) identifiers (see the section "Explicit188renaming macros" below for a detailed explanation on non-R5RS macros).189190Implementation note: this procedure currently just returns its191argument unchanged and is available for writing low-level macros in a192more portable fashion, without hard-coding the signature of a193transformer procedure.194195=== Implicit renaming macros196197Explicit renaming macros generally require the user to perform quite a198few renames, because most identifiers that aren't taken from the input199expression should generally be inserted hygienically. It would make200more sense to give the output expression as-is, and only explicitly201convert those identifiers that you want to treat as ''unhygienic''.202203This can be done with implicit renaming macros. They just swap the204default insertion "mode" from unhygienic to hygienic, so to speak.205Here's the {{cond}} example from the previous section as an ir-macro:206207208 (ir-macro-transformer209 (lambda (exp inject compare)210 (let ((clauses (cdr exp)))211 (if (null? clauses)212 `(quote unspecified)213 (let* ((first (car clauses))214 (rest (cdr clauses))215 (test (car first)))216 (cond ((and (symbol? test)217 (compare test 'else))218 `(begin ,@(cdr first)))219 (else `(if ,test220 (begin ,@(cdr first))221 (cond ,@rest)))))))))222223In this example the identifier {{else}} does ''not'' need to be renamed224before being passed to the comparison predicate because it is already225''implicitly'' renamed. This comparison will also be true if and226only if the test expression is an identifier that denotes the same227thing in the syntactic environment of the expression being transformed228as {{else}} denotes in the syntactic environment in which the {{cond}}229macro was defined. If {{else}} were not renamed before being passed to230the comparison predicate, then it would match a local variable that231happened to be named {{else}}, and the macro would not be hygienic.232233As you can see, the code is a lot clearer because it isn't obscured234by excessive renaming.235236Here's the {{loop}} macro so you can see how hygiene can be broken237with implicit renaming macros:238239 (define-syntax loop240 (ir-macro-transformer241 (lambda (expr inject compare)242 (let ((body (cdr expr)))243 `(call-with-current-continuation244 (lambda (,(inject 'exit))245 (let f () ,@body (f))))))))246247The {{while}} macro is a little trickier: do we inject the call to248{{exit}} or not? Just like the explicit renaming macro version249did ''not'' rename it, we must inject it to allow it to be captured250by the {{loop}} macro:251252 (define-syntax while253 (ir-macro-transformer254 (lambda (expr inject compare)255 (let ((test (cadr expr))256 (body (cddr expr)))257 `(loop258 (if (not ,test) (,(inject 'exit) #f))259 ,@body)))))260261Note: Just like explicit renaming macros, this implementation of262implicit renaming macros allow passing arbitrary expressions to263the injection and comparison procedures. The injection procedure264also return fresh copies of its input.265266267===== ir-macro-transformer268269<procedure>(ir-macro-transformer TRANSFORMER)</procedure>270271This procedure accepts a ''reverse'' syntax transformer, also known as272an ''implicit renaming macro transformer''. This is a transformer which273works almost like er-macro-transformer, except the rename and compare274procedures it receives work a little differently.275276The rename procedure is now called {{inject}} and instead of renaming277the identifier to be resolved in the macro's definition environment,278it will explicitly ''inject'' the identifier to be resolved in the279expansion environment. Any non-injected identifiers in the output280expression produced by the transformer will be implicitly renamed to281refer to the macro's environment instead. All identifiers in the282input expression are of course implicitly injected just like with283explicit renaming macros. See the section above for a more complete284explanation.285286To compare an input identifier you can generally compare to the bare287symbol and only free identifiers will match. In practice, this means288that when you would call e.g. {{(compare (cadr expression) (rename289'x))}} in an ER macro, you simply call {{(compare (cadr expression)290'x)}} in the IR macro. Likewise, an ''unhygienic'' ER macro's291comparison {{(compare sym 'abc)}} should be written as {{(compare sym292(inject 'abc))}} in an IR macro.293294295=== Expanding macros296297==== expand298299<procedure>(expand X)</procedure>300301If {{X}} is a macro-form, expand the macro (and repeat expansion302until expression is a non-macro form). Returns the resulting expression.303304=== Macro helper procedures305306==== begin-for-syntax307308<macro>(begin-for-syntax EXP ...)</macro>309310Equivalent to {{(begin EXP ...)}}, but performs the evaluation of the311expression during macro-expansion time, using the macro environment312rather than the interaction environment.313314You can use this to define your own helper procedures that you can315call from a syntax transformer.316317==== define-for-syntax318319<macro>(define-for-syntax (NAME VAR ...) EXP1 ...)</macro><br>320<macro>(define-for-syntax (NAME VAR1 ... VARn . VARn+1) EXP1 ...)</macro><br>321<macro>(define-for-syntax NAME [VALUE])</macro>322323Defines the toplevel variable {{NAME}} at macro-expansion time. This324can be helpful when you want to define support procedures for use in325macro-transformers, for example.326327Essentially, this is a shorthand for328{{(begin-for-syntax (define ...))}}.329330Note that {{define-for-syntax}} definitions within a module are331implicitly added to that module's import library. Refer to the332documentation on [[Modules#import-libraries|import libraries]]333for more information.334335336==== syntax337338<procedure>(syntax EXPRESSION)</procedure>339340This will quote the {{EXPRESSION}} for use in a syntax expansion. Any341syntactic information will be stripped from the {{EXPRESSION}}.342343344==== strip-syntax345346<procedure>(strip-syntax EXPRESSION)</procedure>347348Strips all syntactical information from {{EXPRESSION}}, returning a349new expression where symbols have all context-information removed.350351You should use this procedure whenever you want to manually construct352new identifiers, which an unhygienic macro can insert. In some cases353it does not ''appear'' to be necessary to strip context information354when you use the macro, but you still should do it. Sometimes355identifiers will not have been renamed (most often at toplevel), but356there may be other contexts in which identifiers ''will'' have been357renamed.358359==== read-with-source-info360361<procedure>(read-with-source-info [port])</procedure>362363Exactly like {{{read}}} from the {{{scheme}}} module, except it364registers the expression it read into the line number database, so365that if {{{(read-with-source-info)}}} returns {{{OBJ}}},366{{{(get-line-number OBJ)}}} will return the line number in {{{port}}}.367368The port argument may be omitted, in which case it defaults to the369value returned by {{current-input-port}}. It is an error to read from370a closed port.371372==== get-line-number373374<procedure>(get-line-number EXPR)</procedure>375376If {{EXPR}} is a pair with the car being a symbol, and line-number377information is available for this expression, then this procedure378returns the associated source file and line number as a string. If379line-number information is not available, then {{#f}} is returned.380381==== syntax-error382383<procedure>(syntax-error [LOCATION] MESSAGE ARGUMENT ...)</procedure>384385Signals an exception of the kind {{(exn syntax)}}. Otherwise identical386to {{error}}.387388389=== Compiler macros390391==== define-compiler-syntax392393<macro>(define-compiler-syntax NAME)</macro><br>394<macro>(define-compiler-syntax NAME TRANSFORMER)</macro><br>395396Defines what is usually called a ''compiler macro'' in Lisp: {{NAME}}397should be the name of a globally or locally bound procedure. Any398direct call to this procedure will be transformed before compilation,399which allows arbitrary rewritings of function calls.400401{{TRANSFORMER}} can be a {{syntax-rules}} expression or a transformer402procedure (as returned by {{er-macro-transformer}} or403{{ir-macro-transformer}}). Returning the original form in an404explicit/implicit-renaming macro or simply "falling trough" all405patterns in a {{syntax-rules}} form will keep the original expression406and compile it normally.407408In the interpreter this form does nothing and returns an unspecified409value.410411Compiler-syntax is always local to the current compilation unit and412can not be exported. Compiler-syntax defined inside a module is not413visible outside of that module.414415{{define-compiler-syntax}} should only be used at top-level. Local416compiler-syntax can be defined with {{let-compiler-syntax}}.417418<enscript highlight=scheme>419(define-compiler-syntax +420 (syntax-rules ()421 ((_) 1)422 ((_ x 0) x) ) )423</enscript>424425If no transformer is given, then {{(define-compiler-syntax NAME)}}426removes any compiler-syntax definitions for {{NAME}}.427428429==== let-compiler-syntax430431<macro>(let-compiler-syntax ((NAME [TRANSFORMER]) ...) BODY ...)</macro>432433Allows definition local compiler macros, which are only applicable434inside {{BODY ...}}. By not providing a {{TRANSFORMER}} expression,435compiler-syntax for specific identifiers can be temporarily disabled.436437---438Previous: [[Module (chicken string)]]439440Next: [[Module (chicken tcp)]]